package com.example.pcl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.pcl.constant.JwtClaimsConstant;
import com.example.pcl.constant.MessageConstants;
import com.example.pcl.exception.ObjectException;
import com.example.pcl.pojo.dto.*;
import com.example.pcl.pojo.entity.Admin;
import com.example.pcl.pojo.entity.Counselors;
import com.example.pcl.pojo.entity.Students;
import com.example.pcl.pojo.entity.Users;
import com.example.pcl.mapper.UsersMapper;
import com.example.pcl.pojo.vo.UserVo;
import com.example.pcl.properties.JwtProperties;
import com.example.pcl.result.PageResult;
import com.example.pcl.service.ICounselorsService;
import com.example.pcl.service.IStudentsService;
import com.example.pcl.service.IUsersService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.pcl.utils.JwtUtil;
import com.example.pcl.utils.ThreadLocalUtil;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 用户表，存储所有用户信息 服务实现类
 * </p>
 *
 * @author xx
 * @since 2024-12-17
 */
@Service
@RequiredArgsConstructor
public class UsersServiceImpl extends ServiceImpl<UsersMapper, Users> implements IUsersService {

    private final JwtProperties jwtProperties;
    private final IStudentsService studentsService;
    private final ICounselorsService counselorsService;

    @Override
    public PageResult<?> pageList(@NotNull UserQueryDto queryDto) {
        String username = queryDto.getUsername();
        String phone = queryDto.getPhone();
        Integer gender = queryDto.getGender();
        Integer accountStatus = queryDto.getAccountStatus();
        Page<Users> usersPage = baseMapper.selectPage(new Page<>(queryDto.getPageNum(), queryDto.getPageSize()), new LambdaQueryWrapper<Users>().eq(ObjectUtils.allNotNull(gender), Users::getGender, gender).like(StringUtils.isNotEmpty(username), Users::getUsername, username).eq(ObjectUtils.allNotNull(accountStatus), Users::getAccountStatus, accountStatus).like(StringUtils.isNotEmpty(phone), Users::getPhone, phone));
        return new PageResult<>(usersPage.getTotal(), usersPage.getRecords().stream().map(user -> BeanUtil.copyProperties(user, UserVo.class)).toList());
    }

    @Override
    public void updateUserInfo(UserDto userDto) {
        if (!updateById(BeanUtil.copyProperties(userDto, Users.class))) {
            throw new ObjectException(MessageConstants.UPDATE_ERR);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteBatch(List<Integer> ids) {
        if (CollectionUtil.isNotEmpty(ids)) {
            List<Integer> userIds = ids.stream().distinct().toList();
            if (!removeBatchByIds(userIds)) {
                throw new ObjectException(MessageConstants.DELETE_ERR);
            }
        }
    }


    @Override
    public void changePassword(ChangePasswordDto changePasswordDto) {
        // 获取当前用户
        Integer userId = ThreadLocalUtil.getId();
        Users users = baseMapper.selectById(userId);
        if (users == null) {
            throw new ObjectException(MessageConstants.USER_NOT_FOUND);
        }
        // 校验旧密码
        String encryptedOldPassword = encryptPassword(changePasswordDto.getOldPassword());
        if (!users.getPassword().equals(encryptedOldPassword)) {
            throw new ObjectException(MessageConstants.PASSWORD_ERR);
        }

        // 校验新旧密码是否一致
        String encryptedNewPassword = encryptPassword(changePasswordDto.getNewPassword());
        if (users.getPassword().equals(encryptedNewPassword)) {
            throw new ObjectException(MessageConstants.PASSWORD_IDENTICAL);
        }

        // 更新密码
        int updated = baseMapper.update(new LambdaUpdateWrapper<Users>().set(Users::getPassword, encryptedNewPassword).eq(Users::getUserId, userId));

        if (updated <= 0) {
            throw new ObjectException(MessageConstants.PASSWORD_UPDATE_FAIL);
        }
    }


    @Override
    public String login(@NotNull LoginDto loginDto) {
        Users user = getOne(new LambdaQueryWrapper<Users>().eq(Users::getUsername, loginDto.getUsername()));
        //用户不存在
        if (user == null) {
            throw new ObjectException("用户不存在，请检查用户名");
        }
        String password = DigestUtil.md5Hex(loginDto.getPassword().getBytes());
        //密码不正确
        if (!user.getPassword().equals(password)) {
            throw new ObjectException("账号或者密码错误，请检查");
        }
        //账号被禁用
        if (user.getAccountStatus().equals(Users.DISABLE)) {
            throw new ObjectException(MessageConstants.ACCOUNT_LOCKED);
        }
        //生成token
        Map<String, Object> claims = new HashMap<>();
        claims.put(JwtClaimsConstant.USER_ID, user.getUserId());
        update(user, new LambdaUpdateWrapper<Users>()
                .set(Users::getLastLoginTime, LocalDateTime.now())
                .eq(Users::getUserId, user.getUserId()));
        return JwtUtil.createJwt(jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl(), claims);
    }

    @Override
    public void register(@NotNull RegisterDto registerDto) {
        // 检查用户名是否已存在
        boolean usernameExists = baseMapper.selectCount(
                new LambdaQueryWrapper<Users>().eq(Users::getUsername, registerDto.getUsername())
        ) > 0;

        if (usernameExists) {
            throw new ObjectException("用户名已被注册");
        }


        boolean phoneExists = baseMapper.selectCount(
                new LambdaQueryWrapper<Users>().eq(Users::getPhone, registerDto.getPhone())
        ) > 0;

        if (phoneExists) {
            throw new ObjectException("邮箱已被注册");
        }

        // 检查学生表中是否存在该用户
        boolean studentExists = studentsService.count(
                new LambdaQueryWrapper<Students>().eq(Students::getStudentNumber, registerDto.getUsername())
        ) > 0;

        if (!studentExists) {
            throw new ObjectException("注册失败：学生信息不存在，请联系管理员");
        }

        // 创建用户对象
        Users newUser = Users.builder()
                .username(registerDto.getUsername())
                .password(encryptPassword(registerDto.getPassword())) // 密码加密
                .phone(registerDto.getPhone())
                .role(Users.STUDENT) // 默认角色：学生
                .accountStatus(Users.NORMAL) // 默认状态：正常
                .build();

        // 插入数据库
        int rows = baseMapper.insert(newUser);
        if (rows != 1) {
            throw new ObjectException("注册失败，请稍后重试");
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void resetPassword(Integer userId) {
        // 查找用户
        Users user = getById(userId);
        if (user == null) {
            throw new ObjectException("用户不存在");
        }
        // 设置默认密码
        user.setPassword(encryptPassword(JwtClaimsConstant.INITIAL_PASSWORD)); // 使用 MD5 加密
        updateById(user); // 更新用户信息
    }

    @Override
    public void addUser(@NotNull UserDto userDto) {

        Integer role = userDto.getRole();

        // 如果是学生，检查学生表中是否存在该用户名
        if (Users.STUDENT.equals(role)) {
            boolean studentExists = studentsService.count(new LambdaQueryWrapper<Students>().eq(Students::getStudentNumber, userDto.getUsername())) > 0;

            if (!studentExists) {
                throw new ObjectException("该用户名不在学生表中，无法添加用户");
            }
        }

        // 如果是心理咨询师，检查心理咨询师表中是否存在该用户名
        if (Users.COUNSELOR.equals(role)) {
            boolean counselorExists = counselorsService.count(new LambdaQueryWrapper<Counselors>()
                    .eq(Counselors::getWorkNumber, userDto.getUsername())) > 0;

            if (!counselorExists) {
                throw new ObjectException("该用户名不在心理咨询师表中，无法添加用户");
            }
        }

        // 检查用户表中是否已存在相同的用户名
        boolean userExists = baseMapper.selectCount(new LambdaQueryWrapper<Users>()
                .eq(Users::getUsername, userDto.getUsername())) > 0;

        if (userExists) {
            throw new ObjectException("该用户已存在");
        }

        // 添加用户，设置初始密码
        Users newUser = BeanUtil.copyProperties(userDto, Users.class)
                .setPassword(DigestUtils.md5DigestAsHex(JwtClaimsConstant.INITIAL_PASSWORD.getBytes()));

        boolean isSaved = baseMapper.insert(newUser) > 0;
        if (!isSaved) {
            throw new ObjectException("添加用户失败，请稍后重试");
        }
    }

    @Override
    public UserVo finById(Integer userId) {
        Users user = getById(userId);
        if (user == null) {
            throw new ObjectException(MessageConstants.USER_NOT_FOUND);
        }
        UserVo userVo = BeanUtil.copyProperties(user, UserVo.class);
        if (user.getUsername().contains("T")) {
            userVo.setRoleId(counselorsService.getOne(new LambdaQueryWrapper<Counselors>()
                    .eq(Counselors::getUserId, userId)).getCounselorId());
        }
        return userVo;
    }


    private @NotNull String encryptPassword(@NotNull String password) {
        return DigestUtils.md5DigestAsHex(password.getBytes());
    }
}
